#include "cgzCLua.h"
#include "cgzCTimer.h"
#include "cgzCTcpWC.h"
#include "cgzCTcpWS.h"
#include "cgzCMysql.h"
#include "cgzClickHouse.h"
#include "cgzCMongo.h"
#include "cgzCHRedis.h"
#include "cgzCHttpC.h"
#include "cgzCHttpS.h"
#include "cgzCThreadPool.h"

clarg::clarg(void *av)
    : type(egzl_nil)
{
    value.pv = av;
}

clarg::clarg(bool av)
    : type(egzl_bool)
{
    value.bv = av;
}

clarg::clarg(int av)
    : type(egzl_int)
{
    value.iv = av;
}

clarg::clarg(long av)
    : type(egzl_long)
{
    value.lv = av;
}

clarg::clarg(long long av)
    : type(egzl_llong)
{
    value.llv = av;
}

clarg::clarg(float av)
    : type(egzl_float)
{
    value.fv = av;
}

clarg::clarg(double av)
    : type(egzl_double)
{
    value.dv = av;
}

clarg::clarg(const char *av)
    : type(egzl_charptr)
{
    value.cv = av;
}

clarg::clarg(const void *av)
    : type(egzl_voidptr)
{
    value.pv = av;
}

clarg::clarg(const char *av, const int len)
    : type(egzl_lstring)
{
    value.cv = av;
    lenght = len;
}

clarg::clarg(const char *av, const int len, egzl_type type)
    : type(type)
{
    value.cv = av;
    lenght = len;
}

clarg::clarg(clargs &array)
    : type(egzl_1array)
{
    value.pv = (void *)&array;
    lenght = array.size();
}

clarg::clarg(clargs2 &array, egzl_type type)
    : type(type)
{
    value.pv = (void *)&array;
    lenght = array.size();
}

clarg::clarg(const web::json::value &js)
    : type(egzl_cpprestjson)
{
    value.pv = (void *)&js;
}

clarg::clarg(const redisReply &reply)
    : type(egzl_redisreply)
{
    value.pv = (void *)&reply;
}

clarg::clarg(const bsoncxx::document::value &mg)
    : type(egzl_mongocvalue)
{
    value.pv = (void *)&mg;
}

clarg::clarg(const std::vector<bsoncxx::document::value> &mgs)
    : type(egzl_mongocarray)
{
    value.pv = (void *)&mgs;
}

// 定义错误处理函数
static int error_handler(lua_State *L)
{
    const char *error = lua_tostring(L, -1);
    if (error == NULL)
    {
        error = "Unknown error";
    }

    // 生成堆栈跟踪
    luaL_traceback(L, L, error, 1);
    return 1; // 返回堆栈跟踪信息
}

cgzCLua::cgzCLua(cgzCThreadPool *pool, const char *name, const char *mode, const char *sid)
    : cgzITask(pool, name, cgzETask::CLua),
      block(nullptr),
      m_mode(mode),
      m_sid(std::stoi(sid))
{
    L = luaL_newstate();
    if (!L)
    {
        cgz_this_error("{}", "Failed to create Lua state");
        return;
    }
    luaL_openlibs(L);
    cgzL_openlibs();
}

cgzCLua::~cgzCLua()
{
    lua_close(L);
}

void cgzCLua::reload(const char *fpatch)
{
    m_patch = fpatch;
    if (luaL_dofile(L, fpatch) != LUA_OK)
    {
        const char *error = lua_tostring(L, -1);
        std::cerr << __FILE__ << ":" << __func__ << ":" << __LINE__ << ": " << "Error: " << error << std::endl;
        lua_pop(L, 1);
        return;
    }
}

void cgzCLua::reload()
{
    fcall("resert", {});
    reload(m_patch.c_str());
}

int cgzCLua::lpushargs(lua_State *L, const clarg &arg)
{
    int nargs = 0;
    switch (arg.type)
    {
    case egzl_nil:
    {
        lua_pushnil(L);
        nargs++;
    }
    break;
    case egzl_bool:
    {
        lua_pushboolean(L, arg.value.bv);
        nargs++;
    }
    break;
    case egzl_int:
    {
        lua_pushinteger(L, arg.value.iv);
        nargs++;
    }
    break;
    case egzl_long:
    {
        lua_pushinteger(L, arg.value.lv);
        nargs++;
    }
    break;
    case egzl_llong:
    {
        lua_pushinteger(L, arg.value.llv);
        nargs++;
    }
    break;
    case egzl_float:
    {
        lua_pushnumber(L, arg.value.fv);
        nargs++;
    }
    break;
    case egzl_double:
    {
        lua_pushnumber(L, arg.value.dv);
        nargs++;
    }
    break;
    case egzl_charptr: // const char *
    {
        lua_pushstring(L, arg.value.cv);
        nargs++;
    }

    break;
    case egzl_voidptr: // const void *
    {
        lua_pushlightuserdata(L, (void *)arg.value.pv);
        nargs++;
    }
    break;
    case egzl_lstring: // const char * with length
    {
        lua_pushlstring(L, arg.value.cv, arg.lenght);
        nargs++;
    }
    break;
    case egzl_jsonstr: // const char * with length
    {
        auto js = web::json::value::parse({arg.value.cv, static_cast<size_t>(arg.lenght)});
        json2table(js);
        nargs++;
    }
    break;
    case egzl_cpprestjson: // web::json::value
    {
        json2table(*static_cast<const web::json::value *>(arg.value.pv));
        nargs++;
    }
    break;
    case egzl_redisreply: // redisReply
    {
        redis2table(*static_cast<const redisReply *>(arg.value.pv));
        nargs++;
    }
    break;
    case egzl_mongocvalue: //
    {
        bson2table(*static_cast<const bsoncxx::document::value *>(arg.value.pv));
        nargs++;
    }
    break;
    case egzl_mongocarray: //
    {
        auto &arr = *static_cast<const std::vector<bsoncxx::document::value> *>(arg.value.pv);
        for (auto &it : arr)
        {
            bson2table(it);
            nargs++;
        }
    }
    break;
    default:
        assert(false);
        break;
    }
    return nargs;
}

int cgzCLua::lpushargs(const clargs &args)
{
    int nargs = 0;
    for (auto &arg : args)
    {
        switch (arg.type)
        {
        case egzl_1array: // clargs
        {
            clargs &array = *(clargs *)arg.value.pv;
            // 获取一个空表
            lua_cgz_newa(L, array.size());
            int j = 0;
            for (auto &it : array)
            {
                lua_pushinteger(L, ++j);
                lpushargs(L, it);
                lua_settable(L, -3);
            }
            nargs++;
        }
        break;
        case egzl_2array: // 二维数组
        {
            clargs2 &array = *(clargs2 *)arg.value.pv;
            // 获取一个空表
            lua_cgz_newa(L, array.size());
            int i = 0;
            for (auto &it1 : array)
            {
                // 创建子项数组
                lua_cgz_newa(L, it1.size());
                // 压入子项数组
                int j = 0;
                for (auto &it2 : it1)
                {
                    lpushargs(L, it2);
                    lua_seti(L, -2, ++j);
                }
                lua_seti(L, -2, ++i);
            }
            nargs++;
        }
        break;
        default:
            nargs += lpushargs(L, arg);
            break;
        }
    }
    return nargs;
}

void cgzCLua::fcall(const char *fname, const clargs &args, int rargs)
{
    // 错误处理函数
    lua_pushcfunction(L, error_handler);
    int efffunidx = lua_gettop(L);
    lua_getglobal(L, fname);
    if (!lua_isfunction(L, -1))
    {
        cgz_this_error("not global function:{}", fname);
        lua_pop(L, 2); // 弹出nil+错误函数
        return;
    }

    int realn = lpushargs(args);
    // 调用全局函数
    if (lua_pcall(L, realn, rargs, efffunidx) != LUA_OK)
    {
        const char *error = lua_tostring(L, -1);
        cgz_this_error("{} {}", fname, error);
        lua_pop(L, 2); // 弹出错误+错误函数
        return;
    }

    // 移除错误函数
    lua_remove(L, efffunidx);
}
void cgzCLua::mcall(const char *mname, const char *fname, const clargs &args, int rargs)
{
    // 压入错误处理函数
    lua_pushcfunction(L, error_handler);
    int efffunidx = lua_gettop(L);
    // 使用 reload 加载模块
    lua_getglobal(L, "reload");
    lua_pushstring(L, mname);
    if (lua_pcall(L, 1, 1, efffunidx) != LUA_OK) // 调用 reload
    {
        const char *error = lua_tostring(L, -1);
        cgz_this_error("reload {}:{} {}", mname, fname, error);
        lua_pop(L, 2); // 弹出错误+错误函数
        return;
    }

    // 获取函数
    lua_getfield(L, -1, fname);
    if (!lua_isfunction(L, -1))
    {
        cgz_this_error("find {}:{} not function", mname, fname);
        lua_pop(L, 2); // 弹出table+错误函数
        return;
    }

    // 准备参数并调用函数
    int realn = lpushargs(args);
    if (lua_pcall(L, realn, rargs, efffunidx) != LUA_OK)
    {
        const char *error = lua_tostring(L, -1);
        cgz_this_error("call {}:{} {}", mname, fname, error);
        lua_pop(L, 3); // 错误消息+错误函数+模块表
        return;
    }

    if (rargs == 0)
    {
        // 弹出模块和错误处理函数
        lua_pop(L, 2);
    }
    else
    {
        lua_remove(L, -rargs - 2); // 移除模块
        lua_remove(L, -rargs - 1); // 移除错误处理函数
    }
}

void cgzCLua::mcall(const char *mname, const clargs &args, int rargs)
{
    // 压入错误处理函数
    lua_pushcfunction(L, error_handler);
    int efffunidx = lua_gettop(L);
    // 使用 reload 加载模块
    lua_getglobal(L, "reload");
    lua_pushstring(L, mname);
    if (lua_pcall(L, 1, 1, efffunidx) != LUA_OK) // 调用 reload
    {
        const char *error = lua_tostring(L, -1);
        cgz_this_error("reload {} {}", mname, error);
        lua_pop(L, 2); // 弹出错误+错误函数
        return;
    }

    // 检查函数
    if (!lua_isfunction(L, -1))
    {
        cgz_this_error("find {} not function", mname);
        lua_pop(L, 1); // 弹出错误函数
        return;
    }

    // 准备参数并调用函数
    int realn = lpushargs(args);
    if (lua_pcall(L, realn, rargs, efffunidx) != LUA_OK)
    {
        const char *error = lua_tostring(L, -1);
        cgz_this_error("call {} {}", mname, error);
        lua_pop(L, 3); // 错误消息+错误函数+模块表
        return;
    }

    if (rargs == 0)
    {
        // 弹出模块和错误处理函数
        lua_pop(L, 2);
    }
    else
    {
        lua_remove(L, -rargs - 2); // 移除模块
        lua_remove(L, -rargs - 1); // 移除错误处理函数
    }
}
bool cgzCLua::rbmcall(const char *mname, const clargs &args)
{
    mcall(mname, args,1);
    bool ret = lua_toboolean(L, -1);
    lua_settop(L, 0);
    return ret;
}

void cgzCLua::ocall(int oref, const char *fname, const clargs &args, int rargs)
{

    lua_pushcfunction(L, error_handler);
    int efffunidx = lua_gettop(L);
    lua_rawgeti(L, LUA_REGISTRYINDEX, oref);
    if (!lua_istable(L, -1))
    {
        cgz_this_error("find {}:{} not table", oref, fname);
        lua_pop(L, 1); // 弹出获取值
        return;
    }

    lua_getfield(L, -1, fname);
    if (!lua_isfunction(L, -1))
    {
        cgz_this_error("find {}:{} not function", oref, fname);
        lua_pop(L, 2); // 弹出对象+非函数值
        return;
    }
    // 对象做第一个参数
    lua_pushvalue(L, -2);

    // 压入其他函数参数(要算一个self参数)
    int realn = lpushargs(args) + 1;
    if (lua_pcall(L, realn, rargs, efffunidx) != LUA_OK)
    {
        const char *error = lua_tostring(L, -1);
        cgz_this_error("call {}:{} {}", oref, fname, error);
        lua_pop(L, 3); // 错误消息+对象表+错误函数
        return;
    }

    // 移除错误函数
    lua_remove(L, efffunidx);
}

bool cgzCLua::rbfcall(const char *fname, const clargs &args)
{
    fcall(fname, args, 1);
    bool ret = lua_toboolean(L, -1);
    lua_settop(L, 0);
    return ret;
}
bool cgzCLua::rbmcall(const char *mname, const char *fname, const clargs &args)
{
    mcall(mname, fname, args, 1);
    bool ret = lua_toboolean(L, -1);
    lua_settop(L, 0);
    return ret;
}

bool cgzCLua::rbocall(int oref, const char *fname, const clargs &args)
{
    ocall(oref, fname, args, 1);
    bool ret = lua_toboolean(L, -1);
    lua_settop(L, 0);
    return ret;
}

int cgzCLua::rifcall(const char *fname, const clargs &args)
{
    fcall(fname, args, 1);
    int ret = lua_tointeger(L, -1);
    lua_settop(L, 0);
    return ret;
}
int cgzCLua::rimcall(const char *mname, const char *fname, const clargs &args)
{
    mcall(mname, fname, args, 1);
    int ret = lua_tointeger(L, -1);
    lua_settop(L, 0);
    return ret;
}

int cgzCLua::riocall(int oref, const char *fname, const clargs &args)
{
    ocall(oref, fname, args, 1);
    bool ret = lua_tointeger(L, -1);
    lua_settop(L, 0);
    return ret;
    return false;
}

std::string cgzCLua::rsocall(int oref, const char *fname, const clargs &args)
{
    ocall(oref, fname, args, 1);
    size_t len = 0;
    auto ret = lua_tolstring(L, -1, &len);
    lua_settop(L, 0);
    return std::string(ret, len);
}

// 调用单例对象成员函数
void cgzCLua::scall(const char *sname, const char *fname, const clargs &args, int rargs)
{
    // 1. 获取模块（相当于 require(sname)）
    lua_getglobal(L, "require");
    lua_pushstring(L, sname);
    if (lua_pcall(L, 1, 1, 0) != LUA_OK)
    {
        const char *error = lua_tostring(L, -1);
        cgz_this_error("require module '{}' failed: {}", sname, error);
        lua_pop(L, 1); // 弹出错误消息
        return;
    }

    // 2. 检查模块是否为table
    if (!lua_istable(L, -1))
    {
        cgz_this_error("module '{}' is not a table", sname);
        lua_pop(L, 1); // 弹出模块
        return;
    }

    // 3. 获取方法（相当于 :fname）
    lua_getfield(L, -1, fname);
    if (!lua_isfunction(L, -1))
    {
        cgz_this_error("method '{}:{}' not found or not function", sname, fname);
        lua_pop(L, 2); // 弹出模块和nil
        return;
    }

    // 4. 准备调用 (self=module)
    lua_pushvalue(L, -2); // 复制模块作为self参数

    // 5. 压入其他参数
    int realn = lpushargs(args);

    // 6. 设置错误处理
    int handler_idx = lua_gettop(L) - (realn + 2);
    lua_pushcfunction(L, error_handler);
    lua_insert(L, handler_idx);

    // 7. 调用方法 (self:fn(...))
    if (lua_pcall(L, realn + 1, rargs, handler_idx) != LUA_OK)
    {
        const char *error = lua_tostring(L, -1);
        cgz_this_error("call '{}:{}' failed: {}", sname, fname, error);
        lua_pop(L, 2); // 弹出错误消息和错误处理函数
        return;
    }

    // 8. 清理栈
    if (rargs == 0)
    {
        lua_pop(L, 2); // 弹出模块和错误处理函数
    }
    else
    {
        // 保留返回值，只弹出模块和错误处理函数
        lua_remove(L, -rargs - 2); // 移除模块
        lua_remove(L, -rargs - 1); // 移除错误处理函数
    }
}

int cgzCLua::riscall(const char *sname, const char *fname, const clargs &args)
{
    scall(sname, fname, args, 1);
    int ret = lua_tointeger(L, -1);
    lua_settop(L, 0);
    return ret;
}

bool cgzCLua::shutdown()
{
    cgzITask::shutdown();
    lua_pushboolean(L, true);
    lua_setglobal(L, "cgzShutdown");
}

bool cgzCLua::mabystop()
{
    // 判断是否又未完成任务
    if (!cgzITask::mabystop())
    {
        return false;
    }

    // 判断是否又未结束协程
    return rbmcall("thread.free", {});
}

bool cgzCLua::run(int64_t nms)
{
    cgzCThreadPool *pTPool = cgzCThreadPool::Instance();

    // 检测添加定时器
    while (!m_runTask.empty())
    {
        auto ok = true;
        auto pTask = m_runTask.front();
        m_runTask.pop_front();
        const cgzITask *iTask = pTPool->getTask(pTask->origin);
        auto tenum = iTask->getTEnum();
        // 定义任务处理函数
        switch (tenum)
        {
        case cgzETask::CTimer:
        {
            auto *pTimer = static_cast<tagTimer *>(pTask);
            rbmcall("single.ctimer", "tick", {pTimer->m_cookid, nms});
            ok = true;
        }
        break;
        case cgzETask::CTcpC:
        {
            ok = run(iTask, static_cast<cgzCLoopC *>(pTask));
        }
        break;
        case cgzETask::CTcpS:
        case cgzETask::CAsioTcpS:
        {
            ok = run(iTask, static_cast<cgzCLoopS *>(pTask));
        }
        break;
        case cgzETask::CTcpGateC:
        case cgzETask::CTcpGateWC:
        {
            ok = rungc(iTask, static_cast<cgzCLoopC *>(pTask));
        }
        break;
        case cgzETask::CTcpGateS:
        case cgzETask::CTcpGateWS:
        {
            ok = rungs(iTask, static_cast<cgzCLoopS *>(pTask));
        }
        break;
        case cgzETask::CTcpWC:
        {
            ok = runwc(iTask, static_cast<cgzCLoopC *>(pTask));
        }
        break;
        case cgzETask::CTcpWS:
        {
            ok = runws(iTask, static_cast<cgzCLoopS *>(pTask));
        }
        break;
        case cgzETask::CHRedis:
        {
            ok = run(iTask, static_cast<cgzCRedisReply *>(pTask));
        }
        break;
        case cgzETask::CMysql:
        {
            ok = run(iTask, static_cast<cgzCMysqlReply *>(pTask));
        }
        break;
        case cgzETask::ClickHouse:
        {
            ok = run(iTask, static_cast<cgzClickHouseReply *>(pTask));
        }
        break;
        case cgzETask::CMongo:
        {
            ok = run(iTask, static_cast<cgzCMongoReply *>(pTask));
        }
        break;
        case cgzETask::CHttpC:
        {
            ok = run(iTask, static_cast<cgzCHttpExecC *>(pTask));
        }
        break;
        case cgzETask::CHttpS:
        {
            ok = run(iTask, static_cast<cgzCHttpLoopS *>(pTask));
        }
        break;
        default:
        {
            cgz_this_error("task {} not support", iTask->getName());
        }
        }

        if (ok)
        {
            pTask->~cgzIData();
            free(pTask);
        }
    }

    return true;
}

bool cgzCLua::todoret(cgzIData *cgzTask)
{
    auto tempid = cgzTask->target;
    cgzTask->target = cgzTask->origin;
    cgzTask->origin = tempid;
    m_retTask.push_back(cgzTask);
    return true;
}

cgzCLua *cgzCLua::getThat(lua_State *L)
{
    lua_getglobal(L, "cgzCLua");
    cgzCLua *that = static_cast<cgzCLua *>(lua_touserdata(L, -1));
    if (!that)
    {
        luaL_error(L, "Invalid cgzCLua instance");
    }
    else
    {
        lua_pop(L, 1);
    }
    return that;
}

void cgzCLua::cgzL_openlibs()
{
    static const luaL_Reg extendlibs[] = {
        {"other", luaopen_other},
        {"mset", luaopen_mset},
        {"tcpC", luaopen_tcpC},
        {"tcpS", luaopen_tcpS},
        {"asioC", luaopen_tcpAsioC},
        {"asioS", luaopen_tcpAsioS},
        {"tcpGateC", luaopen_tcpGateC},
        {"tcpGateS", luaopen_tcpGateS},
        {"tcpGateWC", luaopen_tcpGateWC},
        {"tcpGateWS", luaopen_tcpGateWS},
        {"tcpWC", luaopen_tcpWC},
        {"tcpWS", luaopen_tcpWS},
        {"hiredisC", luaopen_hiredis},
        {"mysqlC", luaopen_mysql},
        {"mongoC", luaopen_mongo},
        {"sqlite3C", luaopen_sqlite3},
        {"httpC", luaopen_httpC},
        {"httpS", luaopen_httpS},
        {"spdlog", luaopen_Spdlog},
        {"clickHouseC", luaopen_clickHouse},
        {NULL, NULL}};

    for (const luaL_Reg *lib = extendlibs; lib->func; lib++)
    {
        luaL_requiref(L, lib->name, lib->func, 1);
        lua_pop(L, 1); /* remove lib */
    }

    lua_pushlightuserdata(L, this);
    lua_setglobal(L, "cgzCLua");
    lua_pushstring(L, m_mode.c_str());
    lua_setglobal(L, "cgzMode");
    lua_pushinteger(L, m_sid);
    lua_setglobal(L, "cgzSid");
}